#pragma once

#include <string>
#include <stack>
#include <stdio.h>

using namespace std;

// Represents an object that writes XML files.
class XmlFileWriter sealed
{
public:
	// Constructor.
	XmlFileWriter();

	// Destructor.
	~XmlFileWriter();

	// Sets the path to the file to write to.
	//		path: the path to the file.
	//		returns: true on success, false otherwise.
	bool SetPath(const string& path);

	// Opens an element.
	//		name: the element name. Must NOT be a temporary string, as a reference to it will be held until the tag is closed.
	void OpenElement(const string& name);

	// Closes current element.
	void CloseElement();

	// Adds an attribute to current element.
	//		name: the attribute name.
	//		value: the value to write.
	void AddAttribute(const string& name, int value);
	void AddAttribute(const string& name, bool value);
	void AddAttribute(const string& name, float value);
	void AddAttribute(const string& name, double value);
	void AddAttribute(const string& name, unsigned int value);
	void AddAttribute(const string& name, const string& value);
	void AddAttribute(const string& name, time_t value);

	// Adds content to current element.
	//		value: the value to write.
	void AddContent(int value);
	void AddContent(bool value);
	void AddContent(float value);
	void AddContent(double value);
	void AddContent(unsigned int value);
	void AddContent(const string& value);
	void AddContent(time_t value);
	void AddContent(const int* buffer, int count);
	void AddContent(const bool* buffer, int count);
	void AddContent(const float* buffer, int count);
	void AddContent(const double* buffer, int count);
	void AddContent(const unsigned char* buffer, int count);
	void AddContentCData(const string& value);

private:
	// Writes indentation tabs into current stream.
	void WriteIndentation(size_t skip = 0);
	// Writes specified string to the file by escaping special XML characters.
	void WriteEscaped(const char* pString, unsigned int dwLength);

	// Represents an XML element.
	struct XmlElement
	{
	public:
		XmlElement(const string& name) : m_Name(name), m_HasAttributes(false), m_HasContent(false), m_HasElements(false) { }

		const string&	m_Name;				// A reference to the element name.
		bool			m_HasAttributes;	// Indicates whether the element has attributes.
		bool			m_HasContent;		// Indicates whether the element has content.
		bool			m_HasElements;		// Indicates whether the element contains elements.
	};

	stack<XmlElement>	m_Elements;			// The stack of open elements.
	FILE*				m_pFile;			// The output file.
};